/* =============================================================
 * Ketchup4j : Squeeze the speed out of your objects. 
 * =============================================================
 *
 * (C) Copyright 2007, by Saverio Miroddi
 *
 * Project Info:  http://tinyhorrorsql.sourceforge.net/
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 3 of the License, or (at 
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 *
 * ---------------------------
 * CacheCleaner.java
 * ---------------------------
 * Author: Saverio Miroddi
 * 
 */
package org.itmozart.ketchup4j.other;

import java.util.HashSet;
import java.util.Set;

import org.itmozart.ketchup4j.cache.ICache;

/**
 * Lanches clean() method of the caches at specified time interval.
 * Caches are accessed in a thread-safe way.
 */
@SuppressWarnings("unchecked")
public class CacheCleaner extends Thread {
//	private static final Logger log = Logger.getLogger(CacheCleaner.class.getName());
	
	public static final long DEFAULT_SLEEP_MS = 30 * 1000;
	private static CacheCleaner singleton;
	
	private Set<ICache> caches;

    private volatile long cleanInterval;
    
    private boolean active;
    
    public static CacheCleaner getInstance() {
    	if (singleton == null) {
    		singleton = new CacheCleaner(DEFAULT_SLEEP_MS);
    		singleton.start();
    		return singleton;
    	}
    	else {
    		return singleton;
    	}
    }
    
    private CacheCleaner(long cleanInterval) {
        this.cleanInterval = cleanInterval;
        caches = new HashSet<ICache>();

        setName(CacheCleaner.class.getSimpleName());
        setDaemon(true);
        
        active = true;
    }

    public void setCleanInterval(long cleanInterval) {
        this.cleanInterval = cleanInterval;
    }
    
    public void setCleanIntervalDebug(long cleanInterval) {
        this.cleanInterval = cleanInterval;
        interrupt();
    }

    public void run() {
        while (active) {
			if (caches.size() > 0) {
				synchronized (caches) {
					for (ICache cache: caches) cache.clean();
				}
			}
			try {
				sleep(cleanInterval);
			}
			catch (InterruptedException e) { }
		}
    }

    /**
	 * <b>It strongly suggested to call this at the end of the cache constructor</b>,
	 * to avoid the (rare) case in which the constructions stops and the control
	 * passes to the cleaner, which inspects the object.
	 */
    public void register(ICache cache) {
        if(cache == null){
            throw new IllegalArgumentException("cache is null");
        }

        boolean isNew;
        
    	synchronized(caches){
        	isNew = caches.add(cache);
        }

    	if(! isNew) {
    		String msg = String.format("Cache id: %s exists", cache.getId());
            throw new IllegalArgumentException(msg);
        }
    }
    
    public boolean unregister(ICache cache) {
        synchronized(caches){
            return caches.remove(cache);
        }
    }
    
    public void shutdown() {
    	active = false;
    	interrupt();
    }
}